package com.share.controller;

import com.share.pojo.*;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/*
    数据绑定:
    一、@ResponseBody 返回中文乱码
    https://www.cnblogs.com/lvbinbin2yujie/p/10611415.html

    二、
 */
@Controller
@RequestMapping("/data")
public class DataBindContoller {

    /*
    一、简单类型
    1、该参数必须有，如同加@RequestParam，因为int不允许为null
    2、  http://localhost:8080/sunxj-springmvc1/data/test1               报500
        http://localhost:8080/sunxj-springmvc1/data/test1?age=abc        报400
        http://localhost:8080/sunxj-springmvc1/data/test1?age=1          正常

    注：注解RequestMapping中produces属性可以设置返回数据的类型以及编码，可以是json或者xml：

     */
//    @RequestMapping(value = "/test1", produces = {"text/plain;charset=utf-8","text/html;charset=utf-8"})
    @RequestMapping(value = "/test1")
    @ResponseBody
//    public String test1( int age) {
    public String test1(@RequestParam(value = "age",required = true) int age) {
        return "age：" + age;
    }

    /*
    二、包装类型
    1、该参数可以没有有，因为Integer允许为null
    2、  http://localhost:8080/sunxj-springmvc1/data/test2          返回null
        http://localhost:8080/sunxj-springmvc1/data/test2?age=abc   报400
        http://localhost:8080/sunxj-springmvc1/data/test2?age=1     正常

     */
    @RequestMapping("/test2")
    @ResponseBody
    public String test2(@RequestParam(value = "age",required = false) Integer age) {

        return "age：" + age;
    }

    /*
    三、数组类型
    1、  http://localhost:8080/sunxj-springmvc1/data/test3?name=1&name=sunxj   返回1-sunxj-
     */
    @RequestMapping("/test3")
    @ResponseBody
    public String test3( String[] name) {
        StringBuilder s = new StringBuilder();
        for(String item: name) {
            s.append(item).append("-");
        }
        return s.toString();
    }

    /*
    四、多层级对象
    1、  http://localhost:8080/sunxj-springmvc1/data/test4?phone=123&dog.name=sunxj
        返回Zoo(address=null, phone=123, dog=Dog(name=sunxj, color=null))
     */
    @RequestMapping("/test4")
    @ResponseBody
    public String test4(Zoo zoo) {
        return zoo.toString();
    }

    /*
    五、相同属性的对象
    1、  http://localhost:8080/sunxj-springmvc1/data/test5?cat.name=mao&dog.name=gou&color=black
        返回  dog:Dog(name=gou, color=black) cat:Cat(name=gou, color=black)

        注：对象的前缀绑定：@InitBinder  + init对象类名
     */
    @RequestMapping("/test5")
    @ResponseBody
    public String test5(Dog dog, Cat cat) {
        System.out.println("test5");
        return "dog:" + dog.toString()+ "    cat:"+cat.toString();
    }
    /*
        1、url参数初始化绑定。仅限于当前的Controller
        2、@InitBinder 中的value绑定url中的参数名
        3、请求时会先加载@InitBinder方法，再去执行@RequestMapping方法
     */
    @InitBinder(value = "dog")
    public void initDog(WebDataBinder binder) {
        System.out.println("初始化dog");
        binder.setFieldDefaultPrefix("dog.");
    }
    @InitBinder("cat")
    public void initCat(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("cat.");
    }


    /*
    六、List数据绑定
    1、  http://localhost:8080/sunxj-springmvc1/data/test6?dogs[0].name=sunxj&dogs[1].name=sunxuejian
        返回  size: 2 内容：DogListForm(dogs=[Dog(name=sunxj, color=null), Dog(name=sunxuejian, color=null)])

    1、  http://localhost:8080/sunxj-springmvc1/data/test6?dogs[0].name=sunxj&dogs[2].name=sunxuejian
        返回  size: 3 内容：DogListForm(dogs=[Dog(name=sunxj, color=null), Dog(name=null, color=null), Dog(name=sunxuejian, color=null)])
     */
    @RequestMapping("/test6")
    @ResponseBody
    public String test6(DogListForm dogListForm) {
        return "size: " + dogListForm.getDogs().size() + "    内容："+ dogListForm.toString();
    }


    /*
    七、Set数据绑定
        目前springmvc对set绑定还不够友好  *慎用*
    1、  http://localhost:8080/sunxj-springmvc1/data/test7?dogs[0].name=sunxj
        返回  size: 1 内容：DogSetForm(dogs=[Dog(name=sunxj, color=null)])

     */
    @RequestMapping("/test7")
    @ResponseBody
    public String test7(DogSetForm dogSetForm) {
        return "size: " + dogSetForm.getDogs().size() + "    内容："+ dogSetForm.toString();
    }

    /*
    八、Map数据绑定
    1、  http://localhost:8080/sunxj-springmvc1/data/test8?dogs['x'].name=sunxj&dogs['Y'].name=sunxuejian
        返回  size: 2 内容：DogMapForm(dogs={Y=Dog(name=sunxuejian, color=null), x=Dog(name=sunxj, color=null)})

     */
    @RequestMapping("/test8")
    @ResponseBody
    public String test8(DogMapForm dogMapForm) {
        return "size: " + dogMapForm.getDogs().size() + "    内容："+ dogMapForm.toString();
    }

    /*
    注： @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)；
        GET方式无请求体，所以使用@RequestBody接收数据时，前端不能使用GET方式提交数据，
        而是用POST方式进行提交。在后端的同一个接收方法里，@RequestBody与@RequestParam()
        可以同时使用，@RequestBody最多只能有一个，而@RequestParam()可以有多个。


    九、json数据绑定
    1、POST请求：http://localhost:8080/sunxj-springmvc1/data/test9
        Headers中：Content-Type=application/json
        Body中：{"name":"sunxj","color":"black"}

     */
    @RequestMapping("/test9")
    @ResponseBody
    public String test9(@RequestBody Dog dog ) {
        System.out.println("##dog:"+dog);
        return dog.toString();
    }


    /*
    注：在类名上加@XmlRootElement，在get方法上加@XmlElement，

    十、xml数据绑定
    1、POST请求：http://localhost:8080/sunxj-springmvc1/data/test10
        Headers中：Content-Type=application/xml
        Body中：<dog>
	                <name>sunxj</name>
	                <color>black</color>
                </dog>

     */
    @RequestMapping("/test10")
    @ResponseBody
    public String test10(@RequestBody Dog dog ) {
        System.out.println("##dog:"+dog);
        return dog.toString();
    }

    /*
    十一、自定义类型转换器  StringToBooleanConverter
    1、 http://localhost:8080/sunxj-springmvc1/data/test11?bool=on
        返回true

     */
    @RequestMapping("/test11")
    @ResponseBody
    public String test11(Boolean bool) {
        System.out.println("##bool:"+bool);
        return bool.toString();
    }

    /*
    十二、自定义类型转换器  PropertyEditor
    1、将Stirng类型的1993-12-22转为Date类型
        CustomDateEditor 这个editor通常被注册到DataBinder.java中的registerCustomEditor()中，
        该方法返回PropertyEditorRegistry.java
        http://localhost:8080/sunxj-springmvc1/data/test12?date1=1993-12-22

     */
    @RequestMapping("/test12")
    @ResponseBody
    public String test12(Date date1) {
        System.out.println("##date1:"+date1);
        return date1.toString();
    }
    /*
        该@InitBinder("date1") 只是在当前的Controller中生效，不是全局的
     */
    @InitBinder("date1")
    public void initDate1(WebDataBinder binder) {
        System.out.println("初始化test1");
        binder.registerCustomEditor(Date.class,
                new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    }

    /*
    十三、自定义类型转换器  Formatter （spring-context.jar提供的包）
    1、MyDateFormatter implements Formatter<Date>
    2、<bean id="convertersAndFormatters" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <property name="formatters">
                <set>
                    <bean class="com.share.convert.MyDateFormatter"></bean>
                </set>
            </property>
        </bean>

        <mvc:annotation-driven conversion-service="convertersAndFormatters">


     3、请求http://localhost:8080/sunxj-springmvc1/data/test13?date2=1993-12-22

     */
    @RequestMapping("/test13")
    @ResponseBody
    public String test13(Date date2) {
        System.out.println("##date2:"+date2);
        return date2.toString();
    }

    /*
    十四、自定义类型转换器  Converter （spring-core.jar提供的包）
    1、MyDateFormatter implements Formatter<Date>
    2、<bean id="convertersAndFormatters" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <property name="converters">
                <set>
                    <bean class="com.share.convert.MyDateConverter"></bean>
                </set>
            </property>
        </bean>

        <mvc:annotation-driven conversion-service="convertersAndFormatters">


     3、请求http://localhost:8080/sunxj-springmvc1/data/test14?date3=1993-12-22

     */
    @RequestMapping("/test14")
    @ResponseBody
    public String test14(Date date3) {
        System.out.println("##date3:"+date3);
        return date3.toString();
    }


    /*
    十五、RESTful
    1、 REST(Resource Representational State Transfer) 资源表现层状态转换
    2、 如果一个架构符合REST原则，就成它为RESTful架构。
        a、RESTful资源---Resource
            文本、图片、音频
        b、RESTful表现层---Representational
            文本：txt、html、xml、json、二进制
            图片：jpg、png
            uri：统一资源定位符，代表资源的位置，并不代表表现形式，具体的表现形式通过
                 http协议的content-type和accept来描述
        c、State Transfer---状态转化。客户端通过HTTP动词，对服务器端资源进行操作，“实现表现层状态转换“
            幂等性：每次http请求相同的参数，相同的uri，产生的结果是相同的
            GET-获取资源
                http：//www.book.com/book/001
            POST-创建资源，不具有幂等性。post指向的并不是资源的本身（其他方法指向的是资源的本身），而是资源的接收者，资源放在body中(如：创建001和002他们具有两个不同的uri，所以不具有幂等性)
                http：//www.book.com/book  （body中有001或002）
            PUT-创建（更新）资源
                http：//www.book.com/book/001  （001存在时，更新；001不存在时，创建）
            DELETE-删除资源
                http：//www.book.com/book/001


    3、RESTful设计
        a、restful的url上要避免动词 如：sunxj.com/show/subject/001 中的show
        b、不同版本的url应该一样 如：sunxj.com/app/1.0、sunxj.com/app/2.0
                            应为：sunxj.com/app  HEADER中version=1.0或2.0

     */
    @RequestMapping("/book")
    @ResponseBody
    public String book(HttpServletRequest request) {

        System.out.println("ContextPath: "+request.getContextPath());
        System.out.println("ServletPath: "+request.getServletPath());
        System.out.println("RequestURL: "+request.getRequestURL());
        System.out.println("RequestURI: "+request.getRequestURI());
        System.out.println("QueryString: "+request.getQueryString());
        System.out.println("PathInfo: "+request.getPathInfo());

        System.out.println("name: " + request.getParameter("name"));

        String contentType = request.getContentType();
        System.out.println("content-type: "+ contentType);
        if(contentType == null){
            return "book.default";
        } else if(contentType.equals("txt")) {
            return "book.txt";
        } else if(contentType.equals("html")) {
            return "book.html";
        }

        return "book.default";
    }

    /*
    http://localhost:8080/sunxj-springmvc1/data/bookget/001
    返回：book-001

     */
    @RequestMapping("/bookget/{id}")
    @ResponseBody
    public String bookGet(@PathVariable("id") String id) {
        System.out.println("id: " + id);
        return "book-" + id;
    }
}
